﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Resources;
using System.Reflection;
using PaintDotNet;
using PaintDotNet.Effects;
using PaintDotNet.PropertySystem;
using PaintDotNet.IndirectUI;
using LibFiltr;

namespace GaussianSeparableFilterPlugin
{
    public class PluginSupportInfo : IPluginSupportInfo
    {
        public string Author
        {
            get
            {
                return "UrFU Radiotechnical facultet";
            }
        }
        public string Copyright
        {
            get
            {
                return "Copyright © 2011";
            }
        }

        public string DisplayName
        {
            get
            {
                return "GaussianSeparableFilterPlugin";
            }
        }

        public Version Version
        {
            get
            {
                return base.GetType().Assembly.GetName().Version;
            }
        }

        public Uri WebsiteUri
        {
            get
            {
                return new Uri("http://paintnoisefilter.codeplex.com/");
            }
        }
    }


    [PluginSupportInfo(typeof(PluginSupportInfo), DisplayName = "GaussianSeparableFilter")]
    public class GaussianSeparableFilterPlugin : PropertyBasedEffect
    {
        private GaussianSeparableFilter _filter;
        private int Radius = 0;
        private double Deviation = 1.0;
        bool _vertical_step_done;
        int _not_processed_rois;
        Surface _tmp;

        public static string StaticName
        {
            get
            {
                return "Gaussian separable filter";
            }
        }

        public static Image StaticIcon
        {
            get
            {
                return new Bitmap(typeof(GaussianSeparableFilterPlugin), "GaussianSeparableFilterPluginIcon.png");
            }
        }

        public static string StaticSubMenuName
        {
            get
            {
                return "Filtr"; // Use for no submenu
                // return "My SubMenu"; // Use for custom submenu
            }
        }

        public GaussianSeparableFilterPlugin()
            : base(StaticName, StaticIcon, StaticSubMenuName, EffectFlags.Configurable)
        {
            this.Radius = 1;
            this.Deviation = 1.0;
        }

        public enum PropertyNames
        {
            Radius,
            Deviation
        }

        protected override PropertyCollection OnCreatePropertyCollection()
        {
            List<Property> props = new List<Property>();

            props.Add(new Int32Property(PropertyNames.Radius, 1, 0, 100));
            props.Add(new DoubleProperty(PropertyNames.Deviation, 1.0, 1.0, 100.0));

            return new PropertyCollection(props);
        }

        protected override ControlInfo OnCreateConfigUI(PropertyCollection props)
        {
            ControlInfo configUI = CreateDefaultConfigUI(props);

            configUI.SetPropertyControlValue(PropertyNames.Radius, ControlInfoPropertyNames.DisplayName, "Radius");
            configUI.SetPropertyControlValue(PropertyNames.Deviation, ControlInfoPropertyNames.DisplayName, "Standard deviation");

            return configUI;
        }

        protected override void OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs)
        {
            this.Radius = newToken.GetProperty<Int32Property>(PropertyNames.Radius).Value;
            this.Deviation = newToken.GetProperty<DoubleProperty>(PropertyNames.Deviation).Value;
            _vertical_step_done = false;

            base.OnSetRenderInfo(newToken, dstArgs, srcArgs);
        }


        protected override void OnCustomizeConfigUIWindowProperties(PropertyCollection props)
        {
            // Change the effect's window title
            props[ControlInfoPropertyNames.WindowTitle].Value = "Gaussian separable filter";
            base.OnCustomizeConfigUIWindowProperties(props);
        }

        protected override unsafe void OnRender(Rectangle[] rois, int startIndex, int length)
        {
            if (length == 0) return;

            if (!_vertical_step_done)
            {
                // init thread sync stuff
                _not_processed_rois = rois.GetLength(0);
                _tmp = DstArgs.Surface.Clone();
                _vertical_step_done = true;
            }

            _filter = new GaussianSeparableFilter(Radius, Deviation);

            // vertical step
            for (int i = startIndex; i < startIndex + length; ++i)
            {
                RenderV(_tmp, SrcArgs.Surface, rois[i]);
            }
            // thread sync
            _not_processed_rois -= length;
            while (_not_processed_rois > 0)
                ;
            // horizontal sync
            for (int i = startIndex; i < startIndex + length; ++i)
            {
                RenderH(DstArgs.Surface, _tmp, rois[i]);
            }
        }

        void RenderH(Surface dst, Surface src, Rectangle rect)
        {
            Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();

            _filter.FilterHorizontal(dst, src, selection, rect);
        }

        void RenderV(Surface dst, Surface src, Rectangle rect)
        {
            Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();

            _filter.FilterVertical(dst, src, selection, rect);
        }
    }
}